package com.lythen.test.geo.es.component;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lythen.test.geo.es.entity.GeoDataEntity;
import com.lythen.test.geo.es.entity.ParentArea;
import com.lythen.test.geo.es.repository.GeoDataRepository;
import org.elasticsearch.index.fielddata.ScriptDocValues;
import org.elasticsearch.index.query.*;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.feature.FeatureCollection;
import org.geotools.geojson.GeoJSON;
import org.geotools.geojson.GeoJSONUtil;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geojson.geom.GeometryJSON;
import org.geotools.geometry.GeometryBuilder;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.geom.impl.CoordinateArraySequence;
import org.locationtech.spatial4j.shape.ShapeFactory;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.geo.GeoJson;
import org.springframework.data.elasticsearch.core.geo.GeoJsonMultiPolygon;
import org.springframework.data.elasticsearch.core.geo.GeoJsonPolygon;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.IndicesOptions;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.stereotype.Service;

import java.io.*;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <h3>geo-elasticsearch</h3>
 * <p></p>
 *
 * @author : lythen
 * @date : 2022-07-14 23:22
 **/
@Service
public class GeoDataService {
    @Autowired
    GeoDataRepository geoDataRepository;
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    public void Insert() throws IOException, ParseException {
        String strGeoJson = ResourceUtil.readStr("广东省.json", Charset.forName("utf-8"));
        JSONObject jsonObject = JSONObject.parseObject(strGeoJson);
        JSONArray features = jsonObject.getJSONArray("features");
        for (Object featureObject : features) {
            JSONObject feature = (JSONObject) featureObject;
            JSONObject properties = feature.getJSONObject("properties");

            GeoDataEntity geoDataEntity = new GeoDataEntity();
            geoDataEntity.setAdcode(properties.getInteger("adcode"));
            geoDataEntity.setName(properties.getString("name"));
            JSONArray pointsArray = properties.getJSONArray("center");
            if (pointsArray != null) {
                GeoPoint center = new GeoPoint(pointsArray.getDouble(1), pointsArray.getDouble(0));
                geoDataEntity.setCenter(center);
            }
            pointsArray = properties.getJSONArray("centroid");
            if (pointsArray != null) {
                GeoPoint centroid = new GeoPoint(pointsArray.getDouble(1), pointsArray.getDouble(0));
                geoDataEntity.setCentroid(centroid);
            }

            geoDataEntity.setChildrenNum(properties.getInteger("childrenNum"));
            geoDataEntity.setLevel(properties.getString("province"));
            JSONObject parentObject = properties.getJSONObject("parent");
            geoDataEntity.setParent(new ParentArea(parentObject.getInteger("adcode")));
            geoDataEntity.setSubFeatureIndex(properties.getInteger("subFeatureIndex"));

            String geometry = feature.getString("geometry");
            GeoJson json = GeoJson.of(geometry);
//            GeometryParser parser = new GeometryParser(true, true, true);
//            XContentParser contentParser = JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY
//                    , DeprecationHandler.THROW_UNSUPPORTED_OPERATION, geometry);
//            contentParser.nextToken();
//            Geometry geometry1 = parser.parse(contentParser);
            geoDataEntity.setGeometry(json);
            geoDataEntity = geoDataRepository.save(geoDataEntity);
            System.out.println(String.format("插入%s的数据", geoDataEntity.getName()));
        }


    }

    public List<GeoDataEntity> query(String cityName) {
        MatchPhraseQueryBuilder matchPhraseQueryBuilder = QueryBuilders.matchPhraseQuery("name", cityName);
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(matchPhraseQueryBuilder);

        Query query = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .build();
        IndexCoordinates indexCoordinates = IndexCoordinates.of("geo-*");

        //SearchHits<GeoDataEntity> searchHits = elasticsearchRestTemplate.search(query,GeoDataEntity.class,indexCoordinates);
        SearchHits<GeoDataEntity> searchHits = elasticsearchRestTemplate.search(query, GeoDataEntity.class);
        long count = elasticsearchRestTemplate.count(query, GeoDataEntity.class);
        System.out.println(count);
        return searchHits.get().map(SearchHit::getContent).collect(Collectors.toList());
    }

    public List<GeoDataEntity> queryMap() throws FactoryException, IOException, TransformException {
        List<Coordinate> coordinates = new ArrayList<>();
        coordinates.add(new Coordinate(110.286279014453, 21.1723459409362));
        coordinates.add(new Coordinate(110.28617121267, 21.1723118713491));
        coordinates.add(new Coordinate(110.286140378218, 21.1723742081948));
        coordinates.add(new Coordinate(110.286049663066, 21.1725575405584));
        coordinates.add(new Coordinate(110.286058401796, 21.1725724430162));
        coordinates.add(new Coordinate(110.286059098954, 21.1725736380944));
        coordinates.add(new Coordinate(110.286059146751, 21.1725737105502));
        coordinates.add(new Coordinate(110.286104289983, 21.1726507405685));
        coordinates.add(new Coordinate(110.286279014453, 21.1723459409362));
//geotools要的坐标，是经度为x，纬度为y，es的坐标刚好相反
        List<Coordinate>  coordinates1 = coordinates.stream().map(x->new Coordinate(x.y,x.x)).collect(Collectors.toList());

        CoordinateArraySequence coordinateArraySequence = new CoordinateArraySequence(coordinates1.toArray(new Coordinate[coordinates1.size()]));
        GeometryFactory factory = new GeometryFactory(null, 4490);

        CoordinateReferenceSystem coordinateReferenceSystem = CRS.decode("EPSG:4490");
       LinearRing linearRing1 = new LinearRing(coordinateArraySequence,factory);
        Polygon polygon1 = new Polygon(linearRing1,null,factory);
        Geometry geometry = (Geometry)polygon1;
        MathTransform transform = CRS.findMathTransform(CRS.decode("EPSG:4490"), CRS.decode("EPSG:4524"),true);
        Geometry transform1 = JTS.transform(geometry, transform);
        System.out.println("area1:"+transform1.getArea());

        org.elasticsearch.geometry.LinearRing linearRing = new org.elasticsearch.geometry.LinearRing(com.google.common.primitives.Doubles.toArray(coordinates.stream().map(x -> x.x).collect(Collectors.toList())),
                com.google.common.primitives.Doubles.toArray(coordinates.stream().map(x -> x.y).collect(Collectors.toList())));
        org.elasticsearch.geometry.Polygon polygon = new org.elasticsearch.geometry.Polygon(linearRing);
        org.elasticsearch.geometry.Geometry esgeometry = (org.elasticsearch.geometry.Geometry) polygon;
        GeoShapeQueryBuilder geoQueryBuilder = QueryBuilders.geoIntersectionQuery("geometry", (org.elasticsearch.geometry.Geometry) esgeometry);

        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(geoQueryBuilder);

        Query query = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .build();
        IndexCoordinates indexCoordinates = IndexCoordinates.of("geo-data*");

        SearchHits<GeoDataEntity> searchHits = elasticsearchRestTemplate.search(query, GeoDataEntity.class, indexCoordinates);
        searchHits.forEach(geoDataEntitySearchHit -> {
            GeoDataEntity content = geoDataEntitySearchHit.getContent();
            GeoJson geometry1 = content.getGeometry();
            try {
                GeometryJSON geometryJSON = new GeometryJSON(15);
                Geometry geom = geometryJSON.read(geometry1.toJson());
                Geometry transform2 = JTS.transform(geom, transform);
                System.out.println("area2:"+transform2.getArea());
            } catch (IOException e) {
                throw new RuntimeException(e);
            } catch (TransformException e) {
                throw new RuntimeException(e);
            }

        });
        return searchHits.get().map(SearchHit::getContent).collect(Collectors.toList());
    }
}
